package toolx

import (
	"fmt"
	"os"
	"strconv"
	"strings"

	"gitee.com/workits/pkgs/configx"
	"gitee.com/workits/pkgs/utilx"
	"github.com/flytam/filenamify"
	inf "github.com/fzdwx/infinite"
	"github.com/fzdwx/infinite/components"
	"github.com/fzdwx/infinite/components/selection/singleselect"
)

// CreateConfig 创建配置
func CreateConfig(projName string) {
	// 项目环境
	projCacheDir := projName + PS + ".workits"
	if !utilx.FsIsExist(projCacheDir) {
		panic("🙅这不是一个workits项目")
	}

	if utilx.FsIsExist(projCacheDir + PS + "application.yaml") {
		existInput := components.NewInput()
		existInput.Prompt = "配置文件已经存在, 是否要覆盖原有配置(y/n)? "
		_ = components.NewStartUp(existInput).Start()
		if strings.ToLower(existInput.Value()) != "y" {
			os.Exit(0)
		}
	} else {
		if err := utilx.CreateFile(projCacheDir+PS+"application.yaml", nil); err != nil {
			panic("🙅配置文件创建失败")
		}
	}

	// 读取项目数据库配置并缓存
	var wkcfg WkCfg
	cfg, err := configx.UnmarshalFiles(projCacheDir, &wkcfg)
	if err != nil {
		panic("🙅配置文件读取失败")
	}

	fmt.Println("🔔 输入`bye`退出配置")

	goModuleInput := components.NewInput()
	goModuleInput.Prompt = "Go Module: "
	defaultName := projName
	if defaultName == "." {
		pwd, err := os.Getwd()
		if err != nil {
			panic(err)
		}
		defaultName = pwd[strings.LastIndex(pwd, PS)+1:]
	}
	goModuleInput.DefaultValue = " 请输入项目的 go module 名称(如: gitee.com/workits/demo, 默认: " + defaultName + ")"
	_ = components.NewStartUp(goModuleInput).Start()
	tryExit(goModuleInput.Value())
	if goModuleInput.Value() == goModuleInput.DefaultValue {
		cfg.Set("go-module", defaultName)
	} else {
		goModule := goModuleInput.Value()
		goModule = strings.ReplaceAll(goModule, " ", "")
		goModule, err = filenamify.Filenamify(goModule, filenamify.Options{Replacement: "/"})
		if err != nil {
			panic("🙅 go module 名称输入错误")
		}
		cfg.Set("go-module", goModule)
	}
Dialect:
	keymap := singleselect.DefaultSingleKeyMap()
	keymap.Choice = keymap.Confirm
	dialectSelect, err := inf.NewSingleSelect(
		[]string{"MySQL/MariaDB", "PostgreSQL", "SQLite"},
		singleselect.WithDisableHelp(),
		singleselect.WithDisableFilter(),
		singleselect.WithPageSize(10),
		singleselect.WithHiddenPaginator(),
		singleselect.WithKeyBinding(keymap),
	).Display("DB Type: ")
	if err != nil || dialectSelect < 0 {
		goto Dialect
	}

	switch dialectSelect {
	case 0:
		cfg.Set("db.dialect", "mysql")
		cfg.Set("db.driver", "mysql")
	case 1:
		cfg.Set("db.dialect", "postgresql")
		cfg.Set("db.driver", "postgres")
	case 2:
		cfg.Set("db.dialect", "sqlite")
		cfg.Set("db.driver", "sqlite")
	}
	if cfg.Get("db.dialect").(string) != "sqlite" {
	DBHost:
		hostInput := components.NewInput()
		hostInput.Prompt = "Host: "
		_ = components.NewStartUp(hostInput).Start()
		tryExit(hostInput.Value())
		if len(hostInput.Value()) == 0 {
			goto DBHost
		}
		cfg.Set("db.host", hostInput.Value())
	DBPort:
		portInput := components.NewInput()
		portInput.Prompt = "Port: "
		_ = components.NewStartUp(portInput).Start()
		tryExit(portInput.Value())
		if port, err := strconv.Atoi(portInput.Value()); err != nil || port == 0 {
			goto DBPort
		} else {
			cfg.Set("db.port", port)
		}
	DBUser:
		userInput := components.NewInput()
		userInput.Prompt = "User: "
		_ = components.NewStartUp(userInput).Start()
		tryExit(userInput.Value())
		if len(userInput.Value()) == 0 {
			goto DBUser
		}
		cfg.Set("db.user", userInput.Value())
	DBPass:
		passInput := components.NewInput()
		passInput.Prompt = "Pass: "
		_ = components.NewStartUp(passInput).Start()
		tryExit(passInput.Value())
		if len(passInput.Value()) == 0 {
			goto DBPass
		}
		cfg.Set("db.pass", passInput.Value())
	}
DBName:
	nameInput := components.NewInput()
	nameInput.Prompt = "DB Name: "
	if cfg.Get("db.dialect").(string) == "sqlite" {
		nameInput.Prompt = "DB Name(SQLite文件路径): "
	}
	_ = components.NewStartUp(nameInput).Start()
	tryExit(nameInput.Value())
	if len(nameInput.Value()) == 0 {
		goto DBName
	}
	cfg.Set("db.name", nameInput.Value())
	// 创建工具配置文件
	if err := cfg.WriteConfig(); err != nil {
		panic("🙅配置文件创建失败")
	}
}

// 尝试退出
func tryExit(command string) {
	if command == "bye" {
		panic(ErrExit)
	}
}
